/**
 * Copyright (c) 2016 coderyuan.com. All Rights Reserved.
 * <p>
 * EShop
 * <p>
 * HibernateBaseDao.java created on 上午10:46
 *
 * @author yuanguozheng
 * @version 1.0.0
 * @since 16/3/1
 */
package com.coderyuan.web.api.kit.database;

import com.coderyuan.web.api.kit.models.PageModel;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import java.util.List;
import java.util.Map;

/**
 * Hibernate基Dao
 *
 * @author yuanguozheng
 */
@Deprecated
public class HibernateBaseDao<T> {

    protected static final String SELECT_HQL = "from %s obj where obj.%s=:para";
    protected static final String SELECT_ALL_HQL = "from %s obj";
    protected static SessionFactory sessionFactory;
    protected String mTableName;
    protected String mIdFieldName;

    public HibernateBaseDao() {
    }

    /**
     * 初始化
     *
     * @param tableName   Entity类
     * @param idFieldName 主键名
     */
    public HibernateBaseDao(Class tableName, String idFieldName) {
        getSessionFactory();
        mTableName = tableName.getSimpleName();
        mIdFieldName = idFieldName;
    }

    public boolean insert(T entity) {
        if (entity == null) {
            return false;
        }
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        try {
            transaction = session.beginTransaction();
            session.save(entity);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return false;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    public boolean update(T entity) {
        if (entity == null) {
            return false;
        }
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        try {
            transaction = session.beginTransaction();
            session.update(entity);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return false;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    public boolean delete(T entity) {
        if (entity == null) {
            return false;
        }
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        try {
            transaction = session.beginTransaction();
            session.delete(entity);
            transaction.commit();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return false;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @SuppressWarnings("unchecked")
    public T findBy(String field, Object param) {
        if (param == null) {
            return null;
        }
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        Object result;
        try {
            transaction = session.beginTransaction();
            Query query = session.createQuery(String.format(SELECT_HQL, mTableName, field));
            query.setParameter("para", param);
            result = query.uniqueResult();
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return null;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (null == result) {
            return null;
        }
        return (T) result;
    }

    @SuppressWarnings("unchecked")
    public List<T> findAllBy(String field, Object param) {
        if (param == null) {
            return null;
        }
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        List result;
        try {
            transaction = session.beginTransaction();
            Query query = session.createQuery(String.format(SELECT_HQL, mTableName, field));
            query.setParameter("para", param);
            result = query.list();
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return null;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (null == result) {
            return null;
        }
        return (List<T>) result;
    }

    public T findById(int id) {
        return findBy(mIdFieldName, id);
    }

    public List<T> findAllWithPage(PageModel page) {
        return findAllBase(page, null);
    }

    public List findAll() {
        return findAllBase(null, null);
    }

    protected List findAllWithQuery(PageModel page, String hql, Object... params) {
        Session session = sessionFactory.openSession();
        Query query = session.createQuery(hql);
        return findAllWithQuery(page, query, session, params);
    }

    protected List findAllWithQuery(PageModel page, Query query, Session userSession, Object... params) {
        Transaction transaction = null;
        List list;
        try {
            transaction = userSession.beginTransaction();
            if (page != null) {
                query.setMaxResults(page.getEveryPage());
                query.setFirstResult(page.getBeginIndex());
            }
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i, params[i]);
            }
            list = query.list();
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return null;
        } finally {
            try {
                if (userSession != null) {
                    userSession.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    protected List findAllWithQuery(PageModel page, String hql, Map<String, Object> params) {
        Session session = sessionFactory.openSession();
        return findAllWithQuery(page, session.createQuery(hql), session, params);
    }

    protected List findAllWithQuery(PageModel page, Query query, Session userSession, Map<String, Object> params) {
        Transaction transaction = null;
        List list;
        try {
            transaction = userSession.beginTransaction();
            if (page != null) {
                query.setMaxResults(page.getEveryPage());
                query.setFirstResult(page.getBeginIndex());
            }
            for (String key : params.keySet()) {
                query.setParameter(key, params.get(key));
            }
            list = query.list();
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return null;
        } finally {
            try {
                if (userSession != null) {
                    userSession.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    protected List findAllBase(PageModel page, String condition) {
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        List list;
        try {
            transaction = session.beginTransaction();
            StringBuilder builder = new StringBuilder();
            builder.append(String.format("from %s", mTableName));
            if (!StringUtils.isEmpty(condition)) {
                builder.append(" ");
                builder.append(condition);
            }
            Query query = session.createQuery(builder.toString());
            if (page != null) {
                query.setMaxResults(page.getEveryPage());
                query.setFirstResult(page.getBeginIndex());
            }
            list = query.list();
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            return null;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    public int count() {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        String hql = "select count(*) from %s";
        Query query = session.createQuery(String.format(hql, mTableName));
        int result = ((Long) query.uniqueResult()).intValue();
        transaction.commit();
        return result;
    }

    private static void getSessionFactory() {
        final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
        try {
            sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}
